package com.example.java_gobang.api;

import com.example.java_gobang.game.*;
import com.example.java_gobang.mapper.UserMapper;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Slf4j
@Component
public class GameAPI extends TextWebSocketHandler {
    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    RoomManager roomManager;

    @Autowired
    OnlineUserManager onlineUserManager;

    @Autowired
    UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        User user = (User) session.getAttributes().get("user");
        GameReadyResponse response = new GameReadyResponse();
        //1.判断是否未登录
        if (user == null) {
            response.setOk(false);
            response.setReason("玩家未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //2.判断玩家是否已经进入房间 （使用房间管理器进行查询）
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            response.setOk(false);
            response.setReason("用户尚未匹配");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //3. 判断多开， （用户是否在其他地方进入游戏
        // 之前准备的 OnlineUserManager
        if (onlineUserManager.getFromGameHall(user.getUserId()) != null ||
        onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
            response.setOk(true);
            response.setReason("禁止多开游戏页面");
            response.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //4.当前玩家上线
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        //5.两个玩家
        synchronized (room) {
            if (room.getUser1() == null) {
                room.setUser1(user);
                room.setWhiteUser(user.getUserId());
                log.info("【afterConnectionEstablished】玩家{}进入房间,作为玩家1，白棋玩家{}",user.getUserName(),user.getUserId());
                return;
            }
            if (room.getUser2() == null) {
                //进到这里说明，玩家1已经进入房间;
                room.setUser2(user);
                log.info("【afterConnectionEstablished】玩家{}进入房间,作为玩家2，黑棋玩家{}",user.getUserName(),user.getUserId());

                //两个玩家都成功进入房间，通知双方对方已就绪
                //通知玩家1
                noticeGameReady(room, room.getUser1(), room.getUser2());
                //通知玩家2
                noticeGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }
        //6.如果此处又有玩家尝试连接到同一个房间，就提示报错
        //这种情况理论上不存在，为让程序更健壮，再做一个判断和提示
        response.setOk(false);
        response.setReason("【afterConnectionEstablished】 房间已满，你不能加入");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(true);
        response.setMessage("gameReady");
        response.setReason("");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(thisUser.getUserId());
        response.setThatUserId(thatUser.getUserId());
        response.setWhiteUser(room.getWhiteUser());
        WebSocketSession session = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        log.info("【handleTextMessage】 收到玩家{}的消息：{}",user.getUserName(),message.getPayload());

        if (user == null) {
            log.info("【handleTextMessage】 用户信息为空，user：{}",user );
            return;
        }

        Room room = roomManager.getRoomByUserId(user.getUserId());
        room.putChess(message.getPayload());

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user = (User) session.getAttributes().get("user");
        log.info("【afterConnectionClosed】 玩家{}已断开连接",user.getUserName());

        if (user == null) {
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (exitSession == session) {
            onlineUserManager.existGameRoom(user.getUserId());
        }
        log.info("【afterConnectionClosed】 当前玩家{}已断开连接",user.getUserName());
        noticeThatUser(user);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (exitSession == session) {
            onlineUserManager.existGameRoom(user.getUserId());
        }
        log.info("【handleTransportError】 当前玩家{}房间连接异常",user.getUserName());
        noticeThatUser(user);

    }

    private void noticeThatUser(User user) throws IOException {
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            //房间已释放,就没有对手
            log.info("【noticeThatUser】 房间已释放");
            return;
        }
        //根据房间,获取对手
        User thatUser = (user == room.getUser1() ? room.getUser2() : room.getUser1());
        //根据对手的userId,获取对手的session，即在线状态
        WebSocketSession thatSession = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if (thatSession == null) {
            log.info("【noticeThatUser】 玩家{}已下线",thatUser.getUserName());
            return;
        }
        //对手在线,就通知对手
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(thatUser.getUserId());
        response.setWinner(thatUser.getUserId());
        thatSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

        //更新用户信息
        int winnerId = response.getWinner();
        userMapper.userWin(winnerId);
        int loserId = user.getUserId();
        userMapper.userLose(loserId);

        //释放房间
        roomManager.remove(room.getRoomId(), room.getUser1().getUserId(), room.getUser2().getUserId());
        log.info("【noticeThatUser】 房间已释放");
    }
}
